import asyncio
import json
import re
from typing import Dict, Any, Optional, List, Union, Tuple
from datetime import datetime, date, time
from enum import Enum
try:
    import openai
except ImportError:
    openai = None

try:
    from anthropic import Anthropic
except ImportError:
    Anthropic = None

try:
    import httpx
except ImportError:
    httpx = None

from ..models.audit_models import AuditRequest, AIAnalysisResult
from ..utils.file_parser import FileParser
from ..utils.logger import get_logger

logger = get_logger(__name__)


class AIProvider(str, Enum):
    """AI服务提供商枚举."""
    OPENAI = "openai"
    ANTHROPIC = "anthropic"
    QIANWEN = "qianwen"
    LOCAL = "local"


class AnalysisType(str, Enum):
    """分析类型枚举."""
    DOCUMENT_PARSING = "document_parsing"
    CONTENT_EXTRACTION = "content_extraction"
    RISK_ASSESSMENT = "risk_assessment"
    RECOMMENDATION = "recommendation"


class DocumentParser:
    """文档解析器 - 专门用于审核申请文档的解析."""
    
    def __init__(self):
        self.file_parser = FileParser()
        self.logger = logger
    
    async def parse_documents(self, documents: List[Dict[str, Any]]) -> Dict[str, str]:
        """解析多个文档并返回提取的内容."""
        parsed_content = {}
        
        for doc in documents:
            doc_id = doc.get("id", "unknown")
            file_path = doc.get("file_path")
            mime_type = doc.get("mime_type")
            
            if not file_path:
                self.logger.warning(f"文档 {doc_id} 缺少文件路径")
                continue
            
            try:
                content = await self.file_parser.parse_file(file_path, mime_type)
                parsed_content[doc_id] = content
                self.logger.info(f"成功解析文档 {doc_id}")
            except Exception as e:
                self.logger.error(f"解析文档失败 {doc_id}: {str(e)}")
                parsed_content[doc_id] = f"解析失败: {str(e)}"
        
        return parsed_content
    
    def extract_key_information(self, content: str) -> Dict[str, Any]:
        """从文本内容中提取关键信息（基础版本，使用正则表达式）."""
        extracted = {}
        
        # 提取时间信息
        time_patterns = [
            r"(\d{4}[年-]\d{1,2}[月-]\d{1,2}[日]?)",  # 日期
            r"(\d{1,2}[:\s]*\d{2})\s*[至到-]\s*(\d{1,2}[:\s]*\d{2})",  # 时间段
            r"(\d{1,2}[点时])\s*[至到-]\s*(\d{1,2}[点时])",  # 时间段（中文）
        ]
        
        for pattern in time_patterns:
            matches = re.findall(pattern, content)
            if matches:
                extracted["time_mentions"] = matches
                break
        
        # 提取人数信息 - 增强版本
        people_patterns = [
            r"(\d+)名?学生",  # 学生人数
            r"(\d+)名?参与者?",  # 参与者
            r"(\d+)人参与",  # 参与人数
            r"预计(\d+)人",  # 预计人数
            r"约\s*(\d+)\s*人",  # 大约人数
            r"(\d+)\s*[人个名位]",  # 通用人数
        ]
        
        participant_numbers = []
        for pattern in people_patterns:
            matches = re.findall(pattern, content)
            if matches:
                participant_numbers.extend([int(m) for m in matches])
        
        if participant_numbers:
            extracted["participant_counts"] = participant_numbers
            extracted["max_participants"] = max(participant_numbers)
        
        # 提取教室容量信息 - 新增
        capacity_patterns = [
            r"容量(\d+)人",  # 容量信息
            r"可容纳(\d+)人",  # 可容纳
            r"座位(\d+)个",  # 座位数
        ]
        
        for pattern in capacity_patterns:
            matches = re.findall(pattern, content)
            if matches:
                extracted["room_capacity"] = int(matches[0])
                break
        
        # 提取设备状态信息 - 新增
        equipment_status_patterns = [
            r"(可用状态|处于可用状态|都.*可用)",  # 设备可用
            r"(暂不可用|不可用|故障)",  # 设备不可用
        ]
        
        for pattern in equipment_status_patterns:
            if re.search(pattern, content):
                extracted["equipment_available"] = "可用" if "可用" in pattern else "不可用"
                break
        
        # 提取教师信息 - 新增
        teacher_patterns = [
            r"教师[：:]\s*([^\s，,。.]{2,10})",  # 教师姓名
            r"任课教师[：:]\s*([^\s，,。.]{2,10})",  # 任课教师
            r"([^\s，,。.]{2,10})\s*老师",  # XX老师
        ]
        
        for pattern in teacher_patterns:
            matches = re.findall(pattern, content)
            if matches:
                extracted["teacher_names"] = matches
                break
        
        # 数据一致性检查 - 新增
        inconsistencies = []
        
        # 检查容量与人数匹配
        if "room_capacity" in extracted and "max_participants" in extracted:
            if extracted["max_participants"] > extracted["room_capacity"]:
                inconsistencies.append(f"预计参与人数({extracted['max_participants']})超过教室容量({extracted['room_capacity']})")
        
        # 检查教师信息一致性
        if "教师证明" in content and "teacher_names" not in extracted:
            inconsistencies.append("提及教师证明但未找到具体教师姓名")
        
        if inconsistencies:
            extracted["data_inconsistencies"] = inconsistencies
        
        # 提取目的关键词
        purpose_keywords = [
            "会议", "培训", "讲座", "研讨", "学术", "教学", "课程",
            "活动", "比赛", "竞赛", "表演", "展示", "答辩", "考试"
        ]
        
        found_purposes = [kw for kw in purpose_keywords if kw in content]
        if found_purposes:
            extracted["purpose_keywords"] = found_purposes
        
        # 提取设备需求
        equipment_keywords = [
            "投影仪", "音响", "麦克风", "话筒", "电脑", "摄像",
            "录像", "直播", "网络", "WiFi", "空调", "桌椅"
        ]
        
        found_equipment = [eq for eq in equipment_keywords if eq in content]
        if found_equipment:
            extracted["equipment_mentions"] = found_equipment
        
        return extracted


class AIAnalyzer:
    """AI智能分析器."""
    
    def __init__(self, provider: AIProvider = AIProvider.OPENAI, 
                 api_key: Optional[str] = None, model: Optional[str] = None):
        self.provider = provider
        self.api_key = api_key
        self.model = model or self._get_default_model()
        self.document_parser = DocumentParser()
        
        # 初始化客户端
        self._init_client()
        
        # 缓存prompt模板
        self.prompt_templates = self._load_prompt_templates()
        
    def _get_default_model(self) -> str:
        """获取默认模型."""
        model_map = {
            AIProvider.OPENAI: "qwen-max-latest",  # 使用通义千问最新模型
            AIProvider.ANTHROPIC: "claude-3-haiku-20240307",
            AIProvider.QIANWEN: "qwen-max-latest",
            AIProvider.LOCAL: "local-llm"
        }
        return model_map.get(self.provider, "qwen-max-latest")
    
    def _init_client(self):
        """初始化AI客户端."""
        try:
            if self.provider == AIProvider.OPENAI:
                if openai is None:
                    logger.warning("OpenAI库未安装，跳过AI客户端初始化")
                    self.client = None
                    return
                # 支持通义千问的OpenAI兼容端点
                base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
                self.client = openai.OpenAI(api_key=self.api_key, base_url=base_url)
            elif self.provider == AIProvider.ANTHROPIC:
                if Anthropic is None:
                    logger.warning("Anthropic库未安装，跳过AI客户端初始化")
                    self.client = None
                    return
                self.client = Anthropic(api_key=self.api_key)
            elif self.provider == AIProvider.QIANWEN:
                if httpx is None:
                    logger.warning("httpx库未安装，跳过AI客户端初始化")
                    self.client = None
                    return
                # 通义千问客户端初始化
                self.client = httpx.AsyncClient(
                    base_url="https://dashscope.aliyuncs.com/api/v1/",
                    headers={"Authorization": f"Bearer {self.api_key}"}
                )
            else:
                self.client = None
                
            logger.info(f"AI客户端初始化成功: {self.provider}")
            
        except Exception as e:
            logger.error(f"AI客户端初始化失败: {str(e)}")
            self.client = None
    
    def _load_prompt_templates(self) -> Dict[str, str]:
        """加载prompt模板."""
        return {
            "information_extraction": """
你是一个专业的教室借用申请分析专家。请分析以下申请材料，提取关键信息。

申请材料内容：
{content}

现有申请信息：
- 申请人：{applicant_name}
- 教室：{classroom_id}
- 申请时间：{start_time} 至 {end_time}
- 使用目的：{usage_purpose}
- 预期人数：{participants_count}

请从申请材料中提取和验证以下信息，以JSON格式返回：
{{
    "extracted_info": {{
        "actual_start_time": "从材料中提取的实际开始时间",
        "actual_end_time": "从材料中提取的实际结束时间",
        "actual_purpose": "从材料中提取的详细使用目的",
        "actual_participants": "从材料中提取的实际参与人数",
        "activity_type": "活动类型分类",
        "special_requirements": "特殊要求和注意事项",
        "organizer_info": "组织者信息",
        "contact_info": "联系方式"
    }},
    "confidence_scores": {{
        "time_accuracy": 0.0-1.0,
        "purpose_clarity": 0.0-1.0,
        "participant_accuracy": 0.0-1.0,
        "overall_confidence": 0.0-1.0
    }},
    "inconsistencies": ["与已有信息不一致的地方列表"],
    "missing_info": ["缺少的重要信息列表"]
}}

请确保返回有效的JSON格式。
""",

            "risk_assessment": """
你是一个教室借用风险评估专家。请对以下申请进行风险评估。

申请信息：
- 申请人类型：{applicant_type}
- 教室：{classroom_id}
- 使用时间：{start_time} 至 {end_time}
- 使用目的：{usage_purpose}
- 参与人数：{participants_count}
- 设备需求：{equipment_needs}

已提取的信息：
{extracted_info}

重要提醒：请仔细分析以下上下文信息，准确提取具体数据：
1. 从房间信息中精确提取容量数字（如"容量50人"表示容量为50人）
2. 从申请描述中精确提取参与人数（如"100名学生"表示100人）
3. 从设备信息中确认设备状态（如"目前都处于可用状态"表示设备可用）
4. 必须基于实际提供的具体信息进行评估，不要说"未知"如果信息已明确提供

数字对比要求：
- 如果房间容量为X人，预计参与Y人，且Y > X，这是严重安全风险
- 必须进行精确的数字比较，不能模糊处理

请评估潜在风险并以JSON格式返回：
{{
    "risk_assessment": {{
        "safety_risk": {{"level": "low/medium/high", "description": "基于实际容量和人数对比的安全风险描述"}},
        "security_risk": {{"level": "low/medium/high", "description": "基于实际情况的安全保密风险描述"}},
        "equipment_risk": {{"level": "low/medium/high", "description": "基于实际设备状态的风险描述"}},
        "facility_risk": {{"level": "low/medium/high", "description": "基于实际设施信息的风险描述"}},
        "policy_compliance": {{"level": "compliant/warning/violation", "description": "基于申请人身份和活动类型的政策合规性"}}
    }},
    "risk_factors": ["列出具体的风险因素，包括具体的数字对比结果"],
    "mitigation_suggestions": ["针对实际风险的缓解建议"],
    "overall_risk_level": "low/medium/high",
    "capacity_analysis": "房间容量X人，预计参与Y人，容量是否充足的具体分析"
}}
""",

            "recommendation": """
你是一个教室借用申请审核专家。基于以下信息，请给出审核建议。

申请基本信息：
{basic_info}

提取的详细信息：
{extracted_info}

风险评估结果：
{risk_assessment}

规则检查结果：
{rule_results}

请提供审核建议，以JSON格式返回：
{{
    "ai_recommendation": "approve/reject/conditional/manual_review",
    "ai_reasoning": "详细的推理过程和依据",
    "confidence_level": 0.0-1.0,
    "key_factors": ["影响决策的关键因素"],
    "suggestions": {{
        "for_applicant": ["给申请人的建议"],
        "for_reviewer": ["给人工审核员的建议"],
        "for_improvement": ["申请改进建议"]
    }},
    "conditions": ["如果是条件通过，列出具体条件"],
    "follow_up_actions": ["后续需要的行动"]
}}
"""
        }
    
    async def analyze_request(self, request: AuditRequest) -> AIAnalysisResult:
        """全面分析审核请求."""
        start_time = datetime.now()
        
        try:
            # 1. 解析文档
            extracted_content = {}
            if request.documents:
                extracted_content = await self.document_parser.parse_documents(request.documents)
            
            # 2. 信息提取
            extracted_info = await self._extract_information(request, extracted_content)
            
            # 3. 风险评估
            risk_assessment = await self._assess_risks(request, extracted_info)
            
            # 4. 生成建议
            recommendation = await self._generate_recommendation(
                request, extracted_info, risk_assessment
            )
            
            # 5. 计算置信度
            confidence_scores = self._calculate_confidence_scores(
                extracted_info, risk_assessment, recommendation
            )
            
            processing_time = (datetime.now() - start_time).total_seconds() * 1000
            
            # 6. 构建结果
            result = AIAnalysisResult(
                extracted_info=extracted_info,
                confidence_scores=confidence_scores,
                ai_recommendation=recommendation.get("ai_recommendation", "manual_review"),
                ai_reasoning=recommendation.get("ai_reasoning", ""),
                risk_assessment=risk_assessment,
                model_name=self.model,
                model_version=self._get_model_version(),
                processing_time_ms=processing_time
            )
            
            logger.info(f"AI分析完成，耗时: {processing_time:.2f}ms")
            return result
            
        except Exception as e:
            processing_time = (datetime.now() - start_time).total_seconds() * 1000
            logger.error(f"AI分析失败: {str(e)}")
            
            # 返回错误结果
            return AIAnalysisResult(
                extracted_info={"error": str(e)},
                confidence_scores={"overall_confidence": 0.0},
                ai_recommendation="manual_review",
                ai_reasoning=f"AI分析异常，需要人工审核: {str(e)}",
                risk_assessment={"error": str(e)},
                model_name=self.model,
                processing_time_ms=processing_time
            )
    
    async def _extract_information(self, request: AuditRequest, 
                                 documents_content: Dict[str, str]) -> Dict[str, Any]:
        """提取信息."""
        try:
            # 合并所有文档内容
            all_content = "\n".join(documents_content.values())
            
            if not all_content.strip():
                # 没有文档内容，使用基础信息提取
                return self.document_parser.extract_key_information(request.usage_purpose)
            
            # 准备prompt
            prompt = self.prompt_templates["information_extraction"].format(
                content=all_content,
                applicant_name=request.applicant_info.get("applicant_name", "未知"),
                classroom_id=request.classroom_id,
                start_time=request.start_time.isoformat(),
                end_time=request.end_time.isoformat(),
                usage_purpose=request.usage_purpose,
                participants_count=request.participants_count
            )
            
            # 调用AI
            response = await self._call_ai_api(prompt)
            
            # 解析响应
            return self._parse_json_response(response, {})
            
        except Exception as e:
            logger.error(f"信息提取失败: {str(e)}")
            # 返回基础提取结果
            return self.document_parser.extract_key_information(request.usage_purpose)
    
    async def _assess_risks(self, request: AuditRequest, 
                          extracted_info: Dict[str, Any]) -> Dict[str, Any]:
        """评估风险."""
        try:
            applicant_info = request.applicant_info
            
            # 获取完整的申请信息包括additional_notes中的房间和人数信息
            additional_context = getattr(request, 'additional_notes', '') or ''
            
            prompt = self.prompt_templates["risk_assessment"].format(
                applicant_type=applicant_info.get("type", applicant_info.get("user_category", "unknown")),
                classroom_id=request.classroom_id,
                start_time=request.start_time.isoformat(),
                end_time=request.end_time.isoformat(),
                usage_purpose=request.usage_purpose,
                participants_count=request.participants_count,
                equipment_needs=request.equipment_needs or [],
                extracted_info=json.dumps(extracted_info, ensure_ascii=False)
            )
            
            # 构建完整的上下文信息，确保AI能看到所有关键数据
            full_context = f"""
上下文信息详细内容：
{additional_context}

关键提取要求：
1. 请从上述信息中精确提取房间容量数字
2. 请从上述信息中精确提取预计参与人数
3. 请从上述信息中确认设备可用状态
4. 请进行容量与人数的数字对比分析
5. 请检查申请人身份与活动类型的匹配性

必须基于实际数据进行分析，不允许说"未知"除非信息确实缺失。
"""
            
            full_prompt = f"{prompt}\n\n{full_context}"
            
            response = await self._call_ai_api(full_prompt)
            return self._parse_json_response(response, {"overall_risk_level": "medium"})
            
        except Exception as e:
            logger.error(f"风险评估失败: {str(e)}")
            return {
                "overall_risk_level": "medium",
                "risk_factors": ["AI风险评估失败"],
                "error": str(e)
            }
    
    async def _generate_recommendation(self, request: AuditRequest,
                                     extracted_info: Dict[str, Any],
                                     risk_assessment: Dict[str, Any]) -> Dict[str, Any]:
        """生成建议."""
        try:
            basic_info = {
                "applicant": request.applicant_info,
                "classroom": request.classroom_id,
                "time": f"{request.start_time} - {request.end_time}",
                "purpose": request.usage_purpose,
                "participants": request.participants_count
            }
            
            prompt = self.prompt_templates["recommendation"].format(
                basic_info=json.dumps(basic_info, ensure_ascii=False),
                extracted_info=json.dumps(extracted_info, ensure_ascii=False),
                risk_assessment=json.dumps(risk_assessment, ensure_ascii=False),
                rule_results="[]"  # 这里应该传入规则检查结果
            )
            
            response = await self._call_ai_api(prompt)
            return self._parse_json_response(response, {
                "ai_recommendation": "manual_review",
                "ai_reasoning": "默认需要人工审核"
            })
            
        except Exception as e:
            logger.error(f"建议生成失败: {str(e)}")
            return {
                "ai_recommendation": "manual_review",
                "ai_reasoning": f"建议生成异常: {str(e)}",
                "confidence_level": 0.0
            }
    
    async def _call_ai_api(self, prompt: str) -> str:
        """调用AI API."""
        try:
            if self.provider == AIProvider.OPENAI:
                return await self._call_openai(prompt)
            elif self.provider == AIProvider.ANTHROPIC:
                return await self._call_anthropic(prompt)
            elif self.provider == AIProvider.QIANWEN:
                return await self._call_qianwen(prompt)
            else:
                return await self._call_local_llm(prompt)
                
        except Exception as e:
            logger.error(f"AI API调用失败: {str(e)}")
            raise
    
    async def _call_openai(self, prompt: str) -> str:
        """调用OpenAI API."""
        response = await asyncio.to_thread(
            self.client.chat.completions.create,
            model=self.model,
            messages=[
                {"role": "system", "content": "你是一个专业的教室借用申请分析专家。"},
                {"role": "user", "content": prompt}
            ],
            temperature=0.3,
            max_tokens=2000
        )
        return response.choices[0].message.content
    
    async def _call_anthropic(self, prompt: str) -> str:
        """调用Anthropic API."""
        response = await asyncio.to_thread(
            self.client.messages.create,
            model=self.model,
            max_tokens=2000,
            temperature=0.3,
            messages=[
                {"role": "user", "content": prompt}
            ]
        )
        return response.content[0].text
    
    async def _call_qianwen(self, prompt: str) -> str:
        """调用通义千问API."""
        payload = {
            "model": self.model,
            "input": {"messages": [{"role": "user", "content": prompt}]},
            "parameters": {"temperature": 0.3, "max_tokens": 2000}
        }
        
        response = await self.client.post("services/aigc/text-generation/generation", json=payload)
        response.raise_for_status()
        
        result = response.json()
        return result["output"]["text"]
    
    async def _call_local_llm(self, prompt: str) -> str:
        """调用本地LLM（占位符实现）."""
        # 这里可以集成本地模型，如Ollama等
        return '{"ai_recommendation": "manual_review", "ai_reasoning": "本地模型未实现"}'
    
    def _parse_json_response(self, response: str, default: Dict[str, Any]) -> Dict[str, Any]:
        """解析JSON响应."""
        try:
            # 尝试提取JSON部分
            json_match = re.search(r'\{.*\}', response, re.DOTALL)
            if json_match:
                json_str = json_match.group(0)
                return json.loads(json_str)
            else:
                # 没有找到JSON格式，返回默认值
                return default
                
        except json.JSONDecodeError as e:
            logger.error(f"JSON解析失败: {str(e)}, 响应内容: {response[:200]}")
            return default
    
    def _calculate_confidence_scores(self, extracted_info: Dict[str, Any],
                                   risk_assessment: Dict[str, Any],
                                   recommendation: Dict[str, Any]) -> Dict[str, float]:
        """计算置信度分数."""
        scores = {
            "information_extraction": 0.8,
            "risk_assessment": 0.7,
            "recommendation": 0.6,
            "overall_confidence": 0.7
        }
        
        # 根据结果质量调整分数
        if "error" in extracted_info:
            scores["information_extraction"] = 0.3
        
        if "error" in risk_assessment:
            scores["risk_assessment"] = 0.3
        
        if recommendation.get("confidence_level"):
            scores["recommendation"] = float(recommendation["confidence_level"])
        
        # 计算总体置信度
        scores["overall_confidence"] = sum([
            scores["information_extraction"] * 0.4,
            scores["risk_assessment"] * 0.3,
            scores["recommendation"] * 0.3
        ])
        
        return scores
    
    def _get_model_version(self) -> Optional[str]:
        """获取模型版本信息."""
        version_map = {
            AIProvider.OPENAI: "GPT-3.5/4.0",
            AIProvider.ANTHROPIC: "Claude-3",
            AIProvider.QIANWEN: "QWen-Plus",
            AIProvider.LOCAL: "Local-1.0"
        }
        return version_map.get(self.provider)


class AIAnalyzerFactory:
    """AI分析器工厂类."""
    
    @staticmethod
    def create_analyzer(provider_config: Dict[str, Any]) -> AIAnalyzer:
        """根据配置创建AI分析器."""
        provider = AIProvider(provider_config.get("provider", "openai"))
        api_key = provider_config.get("api_key")
        model = provider_config.get("model")
        
        if not api_key:
            raise ValueError(f"API密钥未配置，无法初始化AI分析器 (provider: {provider})")
        
        return AIAnalyzer(provider=provider, api_key=api_key, model=model)
    
    @staticmethod
    def get_available_providers() -> List[Dict[str, Any]]:
        """获取可用的AI提供商信息."""
        return [
            {
                "provider": "openai",
                "name": "OpenAI GPT",
                "models": ["gpt-3.5-turbo", "gpt-4", "gpt-4-turbo"],
                "description": "OpenAI的GPT系列模型"
            },
            {
                "provider": "anthropic", 
                "name": "Anthropic Claude",
                "models": ["claude-3-haiku-20240307", "claude-3-sonnet-20240229", "claude-3-opus-20240229"],
                "description": "Anthropic的Claude系列模型"
            },
            {
                "provider": "qianwen",
                "name": "通义千问",
                "models": ["qwen-plus", "qwen-turbo", "qwen-max"],
                "description": "阿里巴巴的通义千问系列模型"
            },
            {
                "provider": "local",
                "name": "本地模型",
                "models": ["local-llm"],
                "description": "本地部署的语言模型"
            }
        ]